#include <time.h>

#include "Common.h"
#include "LinkedList.h"
#include "DetectFinger.h"
#include "ImgProc.h"
#include "LookupTable.h"

#define MAIN_FUNCTION 4

#define WINDOW1 "handpie window 1"
#define WINDOW2 "handpie window 2"
#define WINDOW3 "handpie window 3"

void mainSangin(LPBYTE lpInput, LPWORD lpHue, LPBYTE lpSat, LPBYTE lpInt, int width, int height);
void mainGJKang(LPBYTE lpInput, LPWORD lpHue, LPBYTE lpSat, LPBYTE lpInt, int width, int height);
void mainKyusik();

int main(int argc, char** argv) {
#if   MAIN_FUNCTION==4
  // OpenCV variables
  CvCapture* capture;
  IplImage* image;  // input frame
  IplImage* output1;  // output frame
  IplImage* output2;  // output frame
  IplImage* output3;  // output frame

  // Image buffers
  LPWORD imageRgb565;
  LPWORD imageHue;
  LPBYTE imageSaturation;
  LPBYTE imageIntensity;

  /*
   * temporary variables
   */
  int resolution;
  int i, j, index;
  WORD currentHue;
  BYTE currentSat;
  BYTE currentInt;

  /*
   * running time measuring variables
   */
  clock_t startTime = 0L;
  double elapsedTime = 0;
  char frames = 0;
  int timing = 0;

  /***************
   * main start
   ***************/
  capture = cvCaptureFromCAM(0);

  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, ORG_WIDTH);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, ORG_HEIGHT);
  cvNamedWindow(WINDOW1, CV_WINDOW_AUTOSIZE);
  cvNamedWindow(WINDOW2, CV_WINDOW_AUTOSIZE);
  cvNamedWindow(WINDOW3, CV_WINDOW_AUTOSIZE);

  if (!cvGrabFrame(capture)) {
    printf("camera is NUll");
  }
  image = cvRetrieveFrame(capture);
  output1 = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
  output2 = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
  output3 = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);

  /*
   * memory allocation
   */
  resolution = image->width * image->height;
  imageRgb565 = (LPWORD) malloc(sizeof(WORD) * resolution);
  imageHue = (LPWORD) malloc(sizeof(WORD) * resolution);
  imageSaturation = (LPBYTE) malloc(sizeof(BYTE) * resolution);
  imageIntensity = (LPBYTE) malloc(sizeof(BYTE) * resolution);

  /*
   * processing each frames
   */
  while (cvWaitKey(10) < 0) {
    startTime = clock();

    cvGrabFrame(capture);
    image = cvRetrieveFrame(capture);

    // convert rgb to hsi
    //rgb888to565((LPBYTE) image->imageData, imageRgb565, image->width, image->height);
    //rgb2hsi(imageRgb565, imageHue, imageSaturation, imageIntensity, image->width, image->height);
    rgb888toHsi((LPBYTE) image->imageData, imageHue, imageSaturation, imageIntensity, image->width,
                image->height);
#endif 

    // 여기에 자신의 mainName() 함수를 사용하면 됨
#if MAIN_FUNCTION==0
    mainGJKang((LPBYTE)image->imageData, imageHue, imageSaturation, imageIntensity, image->width, image->height);
#elif MAIN_FUNCTION==1
#elif MAIN_FUNCTION==2
#elif MAIN_FUNCTION==3
    mainKyusik();
#elif MAIN_FUNCTION==4
    mainSangin((LPBYTE) image->imageData, imageHue, imageSaturation, imageIntensity, image->width,
               image->height);
#endif	

#if   MAIN_FUNCTION==4
    // 여기에 자신의 mainName() 함수를 사용하면 됨
    output2->imageData = (char*) imageHue;
    output3->imageData = (char*) imageSaturation;

    cvShowImage(WINDOW1, image);
    cvShowImage(WINDOW2, output2);
    cvShowImage(WINDOW3, output3);

    // fps 계산
    frames++;
    elapsedTime = (elapsedTime + ((double) (clock() - startTime) / CLOCKS_PER_SEC));
    if (elapsedTime >= 1.0) {
      printf("fps: %d\n", frames);
      elapsedTime -= 1.0;
      frames = 0;
    }
  }

  /*
   * release allocation & resources
   */
  free(imageRgb565);
  free(imageHue);
  free(imageSaturation);
  free(imageIntensity);
  cvReleaseImage(&output1);
  cvReleaseImage(&output2);
  cvReleaseImage(&output3);
  cvReleaseCapture(&capture);
  cvDestroyWindow(WINDOW1);
  cvDestroyWindow(WINDOW2);
  cvDestroyWindow(WINDOW3);
#endif
  return 0;

}

void mainSangin(LPBYTE lpInput, LPWORD lpHue, LPBYTE lpSat, LPBYTE lpInt, int width, int height) {
}

void mainGJKang(LPBYTE lpInput, LPWORD lpHue, LPBYTE lpSat, LPBYTE lpInt, int width, int height) {
}



void mainKyusik() {
  int valueR, valueG, valueB, i, j;
  int x1, x2, y1, y2;
  int x, y;
  coordinate_t point;
  areaCoordinate_t interestedArea;
  int range, r;
  int startAndEnd = 0;
  int numberOfThread = 10;
  pthread_t tid[50];
  argumentDataSet_t* argumentsData[50];


  //memory allocation for thread arguments
  for (int i = 0; i < numberOfThread; i++)
  {   
    argumentsData[i] = (argumentDataSet_t*) malloc(sizeof(argumentDataSet_t));
  }   

  IplImage *image;
  CvCapture *capture;

  IplImage *image_binary;
  capture = cvCaptureFromCAM(0);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, IMG_WIDTH);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, IMG_HEIGHT);

  if (!cvGrabFrame(capture)) {
    printf("camera is NUll");
  }
  cvNamedWindow("camera", 0);
  cvResizeWindow("camera", 640, 480);

  while (cvWaitKey(10) < 0) {
    cvGrabFrame(capture);
    image = cvRetrieveFrame(capture);
    image_binary = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 3);
    //printf("getsizs : %d, ipl: %d\n", cvGetSize(image), IPL_DEPTH_8U);

    x1 = 9999;
    x2 = 0;
    y1 = 9999;
    y2 = 0;
    for (i = 0; i < IMG_HEIGHT; i++) {
      for (j = 0; j < IMG_WIDTH; j++) {
        int temp = (i * IMG_WIDTH + j) * 3;
        valueR = image->imageData[temp + 2];
        valueG = image->imageData[temp + 1];
        valueB = image->imageData[temp + 0];

        if (valueR > 95 && valueG > 40 && valueB > 20 &&
        MAX(valueR, MAX(valueG, valueB)) - MIN(valueR, MIN(valueG, valueB)) > 15 &&
        ABS(valueR, valueG) > 15 && valueR > valueG && valueR > valueB) {
          image_binary->imageData[temp + 2] = 255;
          image_binary->imageData[temp + 1] = 255;
          image_binary->imageData[temp] = 255;
        } else {
          image_binary->imageData[temp + 2] = 0;
          image_binary->imageData[temp + 1] = 0;
          image_binary->imageData[temp] = 0;
        }

      }

    }

    erodeImage(image_binary);

    for (i = 0; i < IMG_HEIGHT; i++) {
      for (j = 0; j < IMG_WIDTH; j++) {
        int temp = (i * IMG_WIDTH + j) * 3;
        if (image_binary->imageData[temp] == 255) {
          x1 = MIN(j, x1);
          x2 = MAX(j, x2);
          y1 = MIN(i, y1);
          y2 = MAX(i, y2);
        }
      }
    }

    cvRectangle(image_binary, cvPoint(x1, y1), cvPoint(x2, y2), CV_RGB(255, 0, 0), 5, 8, 0);
    //printf("%d %d %d %d", x1, y1, x2-x1, y2-y1);

    interestedArea.point1.x = x1;
    interestedArea.point1.y = y1;
    interestedArea.point2.x = x2;
    interestedArea.point2.y = y2;

    findCentre(image_binary, point, interestedArea);

    //printf("%d %d\n", point.x, point.y);

    cvCircle(image_binary, cvPoint(point.x, point.y), 10, CV_RGB(0, 255, 0), -1);
    //start threads
	for (int i = 0; i < numberOfThread; i++)
	{
		setArguments(argumentsData[i], image_binary, interestedArea, point, 0.1 + i * 0.05);
		pthread_create(&tid[i], NULL, detectFinger, (void*) argumentsData[i]);
	}


	for (int i = 0; i < numberOfThread; i++)
	{
		pthread_join(tid[i], NULL);
	}


    //printf("------------\n");
    //getchar();
    cvShowImage("camera", image_binary);
    cvReleaseImage(&image_binary);
  }

  cvReleaseCapture(&capture);
  cvDestroyWindow("camera");
  return;
}
